package com.gitee.xmhzzz.component.common.utils;

import com.fasterxml.jackson.core.type.TypeReference;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.gitee.xmhzzz.component.common.exception.DefaultBusinessException;
import com.google.gson.Gson;
import com.google.gson.GsonBuilder;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;

import java.io.IOException;
import java.security.GeneralSecurityException;
import java.security.MessageDigest;
import java.util.*;

/**
  * @ClassName SignUtil
  * @Description 签名
  * @Author wzq
  * @Date 2023/9/23 11:25
  * @Version 1.0
  */
@Slf4j
public class SignUtil {

    private static Gson gson = new GsonBuilder().disableHtmlEscaping().create();

    public static String toJson(Object o) {
        return gson.toJson(o);
    }

    public static <T> T fromJson(String json, Class<T> clazz) {
        return gson.fromJson(json, clazz);
    }

    public static <T>Map<String,Object> BeanToMap(T bean ){
        Map<String, Object> map = new ObjectMapper().convertValue(bean, new TypeReference<Map<String, Object>>() {});
        return map;
    }


    public static <T>boolean validationBySecretKeyCode(T bean,String secretKeyCode,String secretKey) {
        Map<String, Object> map = BeanToMap(bean);
        // 拿出请求签名
        String sign = (String) map.get("sign");
        map.remove("sign");
        // 根据APPID查询的密钥进行重签
        String newSign = getSignBySecretKeyCode(map,secretKeyCode,secretKey,"data");
        // 校验签名
        if (!StringUtils.equals(newSign,sign)) {// APPID查询的密钥进行签名 和 用户签名进行比对
            return false;
        }
        return true;
    }

    public static String getSignBySecretKeyCode(Map<String, Object> params,String secretKeyCode,String secretKey,String bodyKey){
        try {
            // 参数进行字典排序
            StringBuilder sortStr = getFormatParams(params,bodyKey);
            // 将密钥key拼接在字典排序后的参数字符串中,得到待签名字符串。
            sortStr.append(secretKeyCode);
            sortStr.append("=");
            sortStr.append(secretKey);
            String s = sortStr.toString();
            // 使用md5算法加密待加密字符串并转为16进制即为sign
            byte[] bytes = encryptMD5(s);
            // 把二进制转化为大写的十六进制
            return byte2hex(bytes);
        }catch (Exception e){
            DefaultBusinessException.of("生成签名错误");
        }
        return null;
    }

    private static StringBuilder getFormatParams(Map<String, Object> params,String bodyKey) {
        List<Map.Entry<String, Object>> infoIds = new ArrayList<Map.Entry<String, Object>>(params.entrySet());
        Collections.sort(infoIds, new Comparator<Map.Entry<String, Object>>() {
            public int compare(Map.Entry<String, Object> arg0, Map.Entry<String, Object> arg1) {
                return (arg0.getKey()).compareTo(arg1.getKey());
            }
        });
        StringBuilder ret = new StringBuilder();
        for (Map.Entry<String, Object> entry : infoIds) {
            if (entry.getValue() == null || StringUtils.isEmpty(entry.getValue().toString())){
                continue;
            }
            if (bodyKey.equals(entry.getKey())) {
                String dataStr = toJson(entry.getValue()).replace("\\", "");
                if (dataStr.startsWith("\"")) {
                    dataStr = dataStr.substring(1, dataStr.length() - 1);
                }
                dataStr = sortJsonStr(dataStr);
                // log.info("sortJsonStr :{}",dataStr);
                ret.append(entry.getKey());
                ret.append("=");
                ret.append(dataStr);
                ret.append("&");
                continue;
            }
            ret.append(entry.getKey());
            ret.append("=");
            ret.append(entry.getValue());
            ret.append("&");
        }
        return ret;
    }

    public static String sortJsonStr(String dataStr) {
        Map map = fromJson(dataStr, Map.class);
        map = sortMapByKey(map);
        return toJson(map);
    }

    private static Map<String, String> sortMapByKey(Map<String, String> map) {
        if (map == null || map.isEmpty()) {
            return null;
        }
        Map<String, String> sortMap = new TreeMap<>(new Comparator<String>() {
            @Override
            public int compare(String o1, String o2) {
                return o1.compareTo(o2);
            }
        });
        sortMap.putAll(map);
        return sortMap;
    }

    public static byte[] encryptMD5(String data) throws IOException
    {
        return encryptMD5(data.getBytes("UTF-8"));
    }

    public static byte[] encryptMD5(byte[] data) throws IOException
    {
        try
        {
            MessageDigest md = MessageDigest.getInstance("MD5");
            byte[] bytes = md.digest(data);
            return bytes;
        }
        catch (GeneralSecurityException var3)
        {
            throw new IOException(var3.toString());
        }
    }

    public static String byte2hex(byte[] bytes)
    {
        StringBuilder sign = new StringBuilder();
        for(int i = 0; i < bytes.length; ++i)
        {
            String hex = Integer.toHexString(bytes[i] & 255);
            if(hex.length() == 1)
            {
                sign.append("0");
            }

            sign.append(hex);
        }

        return sign.toString();
    }

    public static String byte2hexUpperCase(byte[] bytes)
    {
        StringBuilder sign = new StringBuilder();
        for(int i = 0; i < bytes.length; ++i)
        {
            String hex = Integer.toHexString(bytes[i] & 255);
            if(hex.length() == 1)
            {
                sign.append("0");
            }

            sign.append(hex.toUpperCase());
        }

        return sign.toString();
    }




}
